/*
	Copyright (c) 2007, ANYwebcam.com Pty Ltd. All rights reserved.

	The software in this package is published under the terms of the BSD style 
	license, a copy of which has been included with this distribution in the 
	license.txt file.
*/
package com.anywebcam.di
{
	/**
	 * Interface for Containers that manage dependency injection for components
	 */
	public interface DIContainer
	{
		// todo: revise the examples and support cases
		/**
		 * Registers an implementation or an instance with this container. 
		 * This is the preferred method for registering classes and instances.
		 * 
		 * @param args
		 * @return The Component  for the registered component
		 * 
		 * @example Example Component Registration
		 * <listing version="3.0">
		 * var container:DIContainer = new DefaultDIContainer({ cache:true, injectionType: 'setter' });
		 * 
		 * // Register a concrete Class using itself as the key
		 * container.register( Log );
		 * 
		 * // Register a Class using an interface as the key
		 * container.register( Configuration, E4XConfiguration );
		 * 
		 * // Register a Class using an interface as the key, include setter properties
		 * container.register( AnInteface, TheImplementationOfAnInterface, ['someProperty'] ); 
		 * 
		 * // Register a Class using a specific component 
		 * container.register( new ConstructorInjectionComponent( AnotherInterface, AnotherImplementation ) );
		 * 
		 * // Register an instance
		 * container.register( new InstanceOfSomething() );
		 * 
		 * // Register an instance with a key
		 * container.register( InterfaceOfSomething, new InstanceOfSomething() );
		 * 
		 * </listing> 
		 */
		function register( ...args ):DIComponent;
		
		/**
		 * Registers a Component
		 * 
		 * @param component The DIComponent instance
		 * @param args Additional parameters to be used by the DIContainer
		 * @return The Component for the registered component
		 * @example Example Component Registration
		 * <listing version="3.0">
		 * // register an instance
		 * container.registerComponent( new InstanceComponent( new ClassThatShouldBeUsedAsASingleton() ) );
		 * </listing>
		 */
		function registerComponent( component:DIComponent, ...args ):DIComponent;
		
		/**
		 * Registers an implementation
		 * 
		 * @param key The name used to identify this implementation
		 * @param implementation The class implementation
		 * @param args Additional parameters to be used by the Component
		 * @return The Component for the registered component
		 * @example Example Component Registration
		 * <listing version="3.0">
		 * // register an instance
		 * container.registerType( AnInterface, TheImplementation );
		 * </listing>
		 */
		function registerType( key:Object, type:Class, ...args ):DIComponent;
		
		/**
		 * Registers an instance
		 * 
		 * @param key The name used internally to identify this instance
		 * @param instance The object that is being registered
		 * @param args Additional parameters to be used by the 
		 * @return The Component for the registered component
		 * @example Example Component Registration
		 * <listing version="3.0">
		 * // register an instance
		 * container.registerInstance( new ClassInstance );
		 * </listing>
		 */
		function registerInstance( key:Object, instance:Object, ...args ):DIComponent;
		
		/**
		 * Unregisters an instance from the container
		 */
		function unregisterComponent( component:DIComponent ):DIComponent;
		
		/**
		 * Requests the container to provide an implementation of the supplied interface/class or key identifier. 
		 * 
		 * @param type The interface or class which the returned object must implement
		 * @return An instance of the key implementation
		 * @example Examples of using getInstance
		 * <listing version="3.0">
		 * // get an instance by key
		 * var service:HTTPService = container.getInstance( 'service.member.authenticate' ) as HTTPService;
		 * // get an instance by type
		 * var config:Configuration = container.getInstance( Configuration ) as Configuration;
		 * </listing>
		 */
		function getInstance( key:Object ):Object;
		
		/**
		 * Requests the container to provide an implementation of the supplied key identifier. 
		 * 
		 * @param type The key identifier for which to return an instance of 
		 * @return An instance of the key implementation
		 * @example Examples of using getInstance
		 * <listing version="3.0">
		 * // get an instance by key
		 * var service:HTTPService = container.getInstance( 'service.member.authenticate' ) as HTTPService;
		 * </listing>
		 */
		function getInstanceByKey( key:Object ):Object;
		
		/**
		 * Requests the container to provide an implementation of the supplied interface/class. 
		 * 
		 * @param type The Interface or Class which the returned object must implement
		 * @return An instance of the type implementation
		 * @example Examples of using getInstance
		 * <listing version="3.0">
		 * // get an instance by type
		 * var config:Configuration = container.getInstance( Configuration ) as Configuration;
		 * </listing>
		 */
		function getInstanceByType( type:Class ):Object;
		
		/**
		 * Get a Component by its key
		 * 
		 * @param key The key (String identifier, Class or interface) used to register the component
 		 * @return The Component registered with the specified key, or null
		 */
		function getComponent( key:Object ):DIComponent;
		
		/**
		 * Indicates if there is a component with the key or type in this container
		 *
		 * @param keyOrType The key (String identifier, Class or interface) user to register the component
		 * @return True the this container contains a component for that key or type, false otherwise.
		 */
		function hasComponent( keyOrType:Object ):Boolean;
		
		/**
		 * Returns all the registered Components
		 * 
		 * @return Array of all the registered DIComponents
		 */
		function get components():Array; // of DIComponent
		
		/**
		 * Object hash of options the DIContainer may use to do its thing
		 */
		function get options():Object;
		function set options( value:Object ):void;
	}
}